import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef, Inject, Injector } from '@angular/core';

@Inject({})
export class VirtualScrollAsyncComponent implements OnInit {
  asyncData: string[];
  asyncValue: string = '';
  loading = false;
  panelLoading = false;
  inputValue: string;
  private cdr: ChangeDetectorRef;
  private asyncIndex = 100;

  constructor(inject: Injector) {
    this.cdr = inject.get(ChangeDetectorRef);
  }

  ngOnInit(): void {
    this.asyncData = [];
  }

  inputChange(e: string): void {
    this.loading = true;
    this.inputValue = e;
    this.asyncIndex = 10;
    this.initData(
      e,
      data => {
        this.loading = false;
        this.asyncData = data;
        this.cdr.markForCheck();
      },
      this.asyncIndex,
      0
    );
  }

  initData(value: string, cb: (arr: string[]) => void, length = 100, index = 0): void {
    let arr = [];
    if (value.length < 5) {
      arr = Array.from({ length }).map((_, key) => this.asyncValue + (index + key));
    } else {
      arr = [];
    }

    setTimeout(() => {
      cb(arr);
    }, 500);
  }

  asyncScroll(): void {
    if (this.panelLoading) {
      return;
    }
    this.panelLoading = true;
    const offsetIndex = 10;
    this.initData(
      this.inputValue,
      data => {
        this.asyncData = [...this.asyncData, ...data];
        this.asyncIndex += offsetIndex;
        this.panelLoading = false;
        this.cdr.markForCheck();
      },
      offsetIndex,
      this.asyncIndex
    );
  }
}

@Component({
  templateUrl: './virtual-scroll.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class VirtualScrollComponent extends VirtualScrollAsyncComponent implements OnInit {
  data: string[];
  value: string = '';
  index = 100;

  constructor(inject: Injector) {
    super(inject);
  }

  ngOnInit(): void {
    super.ngOnInit();
    this.data = this.getData();
  }

  scroll(): void {
    const offsetIndex = 10;
    this.data = [...this.data, ...this.getData(offsetIndex, this.index)];
    this.index += offsetIndex;
  }

  getData(len: number = 100, index: number = 0): string[] {
    return Array.from({ length: len }).map((_, key) => `item${key + index}`);
  }
}
